// 初识泛型
function identity<T>(arg: T): T{
  return arg
}

console.log(identity('string'))
console.log(identity(123))
console.log(identity(true))
console.log(identity({name: 'hugo'}))
console.log(identity([1, 'str', true]))

// 多个类型参数
function extend<T, U>(first: T, second: U): T & U{
  for(const key in second){
    (first as T & U)[key] = second[key] as any
  }
  return first as T & U
}

// imooc 泛型 for: https://coding.imooc.com/lesson/495.html#mid=42128
function echo<T>(arg: T): T{
  return arg
}
const rs = echo(true)

function swap<T, U>(tuple: [T, U]): [U, T]{
  return [tuple[1], tuple[0]]
}
const rs2 = swap(['string', 23])
console.log(rs2)

// 泛型约束
function echoWithArr<T>(arg: T[]): T[]{
  console.log(arg.length)
  return arg
}
const arrs = echoWithArr([1,2,3,4])
console.log(arrs)


interface IWithLength{
  length: number
}

function echoWithLength<T extends IWithLength>(arg: T): T{
  console.log(arg.length)
  return arg
}

const str = echoWithLength('str')
const obj2 = echoWithLength({length: 10, width: 20})
const arr2 = echoWithLength([1,2,3,4])
// const num3 = echoWithLength(1214)

// 泛型在类和接口中使用
class Queue<T>{
  private data: T[] = [];
  push(item: T){
    return this.data.push(item)
  }
  pop(){
    return this.data.shift()
  }
}

const queue = new Queue<number>()
queue.push(1)
console.log(queue.pop())

interface KeyPair<T, U>{
  key: T,
  value: U
}
let kp1: KeyPair<number, string> = {key: 1, value: 'string'}
let kp2: KeyPair<string, number> = {key: 'str', value: 2}
let arr3: number[] = [1,2,3]
let arr4: Array<number> = [1,2,3]


// 类型别名
type PlusType = (x: number, y: number) => number

let sum2: PlusType
const rs3 = sum2(3,3)